package com.dsg.controller.apply;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dsg.common.constants.DsgStatusConstant;
import com.dsg.common.security.SystemAuthorizingUser;
import com.dsg.common.util.SingletonLoginUtils;
import com.dsg.common.util.UUIDGenerator;
import com.dsg.common.util.toolbox.CollectionUtil;
import com.dsg.common.util.toolbox.DateUtil;
import com.dsg.common.util.toolbox.StringUtil;
import com.dsg.entity.apply.DsgApplyPay;
import com.dsg.entity.apply.DsgApplyStatus;
import com.dsg.entity.approve.DsgApproveCase;
import com.dsg.entity.model.bank.DsgBankDetailModel;
import com.dsg.service.account.IDsgAccountSettingService;
import com.dsg.service.apply.IDeductOneYuanService;
import com.dsg.service.apply.IDsgApplyStatusService;
import com.dsg.service.approve.IDsgApproveCaseService;
import com.dsg.support.LeveldbAccess;
import com.dsg.util.DsgUtils;
import com.dsg.util.RRException;
import com.dsg.util.verify.VerifyHolder;
import com.dsg.util.verify.impl.NotEmptyVerify;
import com.dsg.workflow.WorkflowEngine;
import com.dsg.workflow.WorkflowService3;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @program: erp
 * @description: 上載過1元
 * @author: 賴利榮
 * @create: 2020-10-13 19:21
 */
@Slf4j
public class UploadDeductOneYuan extends AnalysisEventListener<DsgBankDetailModel> {

    private IDeductOneYuanService deductOneYuanService;
    private IDsgApplyStatusService dsgApplyStatusService;
    private IDsgAccountSettingService dsgAccountSettingService;
    private IDsgApproveCaseService caseService;
    private WorkflowEngine engine;
    private List<String> errorList = new ArrayList();
    private VerifyHolder verifyHolder;
    private int totalSize = 1;
    private List<DsgApplyPay> list = new ArrayList<>();
    private LeveldbAccess leveldbAccess;
    /**
     * 按每1000個一組分割
     */
    private final Integer maxNumber = 1000;


    public UploadDeductOneYuan(IDeductOneYuanService deductOneYuanService, IDsgApplyStatusService dsgApplyStatusService,
                               IDsgApproveCaseService caseService, IDsgAccountSettingService dsgAccountSettingService, WorkflowEngine engine, LeveldbAccess leveldbAccess) {
        this.deductOneYuanService = deductOneYuanService;
        this.dsgApplyStatusService = dsgApplyStatusService;
        this.dsgAccountSettingService = dsgAccountSettingService;
        this.caseService = caseService;
        this.engine = engine;
        this.leveldbAccess = leveldbAccess;
        //數據格式校驗
        verifyHolder = new VerifyHolder(DsgBankDetailModel.class, errorList);
        verifyHolder.addVerify(new NotEmptyVerify());
    }


    @Override
    public void invoke(DsgBankDetailModel dsgBankDetailModel, AnalysisContext analysisContext) {
        log.info("解析到一條數據:{}", JSONObject.toJSON(dsgBankDetailModel));
        totalSize++;
        try {
            verifyHolder.check(dsgBankDetailModel, totalSize);
        } catch (Exception e) {
            log.error("檢驗數據異常:", e);
            throw new RRException("檢驗數據異常", e);
        }
        DsgApplyPay dsgApplyPay = new DsgApplyPay();
        dsgApplyPay.setDdaNumber(dsgBankDetailModel.getFlowNo());
        if (StringUtil.isNotEmpty(dsgBankDetailModel.getResponse())) {
            switch (dsgBankDetailModel.getResponse()) {
                //成功
                case DsgStatusConstant.EXCEL_APPROVED:
                    //成功已過簽賬額
                case DsgStatusConstant.EXCEL_DECLINED:
                    dsgApplyPay.setDedStatus(DsgApplyStatus.AppStatus.success.getCode().intValue());
                    dsgApplyPay.setEffectTime(DateUtil.parse(dsgBankDetailModel.getTranDate(), "DDMMYY"));
                    break;
                //信用咭已不能使用
                case DsgStatusConstant.EXCEL_PICKUP:
                    //信用咭已不能使用
                case DsgStatusConstant.EXCEL_INVALID_DATA:
                    dsgApplyPay.setDedStatus(DsgApplyStatus.AppStatus.fail.getCode().intValue());
                    break;
            }
        }
        list.add(dsgApplyPay);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        if (CollectionUtil.isNotEmpty(errorList)) {
            throw new RRException(errorList.toString());
        } else {
            if (CollectionUtil.isNotEmpty(list)) {
                List<String> keyList = new ArrayList<>();
                String oid = UUIDGenerator.getUUID();
                SystemAuthorizingUser user = SingletonLoginUtils.getSystemUser();
                try {
                    List<String> numberList = list.stream().map(DsgApplyPay::getDdaNumber).collect(Collectors.toList());
                    List<List<String>> splitList = DsgUtils.splitList(numberList, maxNumber);
                    //防止SQL in 超过1000 分割查询后缓存
                    for (List<String> ddaNumberList : splitList) {
                        //繳款資料并缓存
                        QueryWrapper<DsgApplyPay> payQueryWrapper = new QueryWrapper<>();
                        payQueryWrapper.eq("ENT_CODE", user.getOrgCode());
                        payQueryWrapper.eq("DED_STATUS", DsgApplyStatus.AppStatus.haveInHand.getCode());
                        payQueryWrapper.in("DDA_NUMBER", ddaNumberList);
                        List<DsgApplyPay> dsgApplyPayList = deductOneYuanService.list(payQueryWrapper);
                        dsgApplyPayList.forEach(I -> {
                            String key = leveldbAccess.genCacheKey(oid, DsgApplyPay.class.getSimpleName(), I.getDdaNumber());
                            leveldbAccess.put(key, I);
                            keyList.add(key);
                        });
                        //業務申請單狀態
                        List<DsgApplyStatus> dsgApplyStatusList = deductOneYuanService.selectDsgApplyStatus(user.getOrgCode(), ddaNumberList);
                        Map<String, List<DsgApplyStatus>> dsgApplyStatusMap = dsgApplyStatusList.stream().collect(Collectors.groupingBy(I -> I.getDdaNumber()));
                        for (String statusKey : dsgApplyStatusMap.keySet()) {
                            String key = leveldbAccess.genCacheKey(oid, DsgApplyStatus.class.getSimpleName(), statusKey);
                            leveldbAccess.put(key, dsgApplyStatusMap.get(statusKey));
                            keyList.add(key);
                        }
                    }
                    List<DsgApplyPay> upDsgApplyPay = new ArrayList<>();
                    List<DsgApplyStatus> upDsgApplyStatus = new ArrayList<>();
                    //處理導入數據
                    for (DsgApplyPay pay : list) {
                        String key = leveldbAccess.genCacheKey(oid, DsgApplyPay.class.getSimpleName(), pay.getDdaNumber());
                        DsgApplyPay dsgApplyPay = leveldbAccess.get(key);
                        if (dsgApplyPay != null) {
                            pay.setOid(dsgApplyPay.getOid());
                            pay.setPayStatus(DsgApplyPay.PAY_STATUS_IN_USE);
                            upDsgApplyPay.add(pay);
                        }
                        key = leveldbAccess.genCacheKey(oid, DsgApplyStatus.class.getSimpleName(), pay.getDdaNumber());
                        List<DsgApplyStatus> dsgApplyStatusList = leveldbAccess.get(key);
                        if (CollectionUtil.isNotEmpty(dsgApplyStatusList)) {
                            for (DsgApplyStatus dsgApplyStatus : dsgApplyStatusList) {
                                if (DsgApplyStatus.AppStatus.success.getCode().intValue() == pay.getDedStatus().intValue()) {
                                    dsgApplyStatus.setIsDedu(DsgApplyStatus.AppStatus.yes.getCode());
                                } else {
                                    dsgApplyStatus.setIsDedu(DsgApplyStatus.AppStatus.no.getCode());
                                }
                                upDsgApplyStatus.add(dsgApplyStatus);
                            }
                        }

                    }
                    if (CollectionUtil.isNotEmpty(upDsgApplyPay)) {
                        deductOneYuanService.updateBatchById(upDsgApplyPay);
                    } else {
                        throw new RRException("查詢無繳款資料！");
                    }
                    if (CollectionUtil.isNotEmpty(errorList)) {
                        throw new RRException(errorList.toString());
                    }
                    if (CollectionUtil.isNotEmpty(upDsgApplyStatus)) {
                        dsgApplyStatusService.updateBatchById(upDsgApplyStatus);
                        //推實例
                        upDsgApplyStatus.forEach(I -> {
                            if (DsgApplyStatus.AppStatus.yes.getCode().intValue() == I.getIsDedu().intValue()) {
                                DsgApproveCase approveCase = caseService.getCase(WorkflowService3.NODE_DEDUCT_ONE, I.getAppNo());
                                if (approveCase == null) {
                                    throw new RRException("對單CASE不存在");
                                }
                                try {
                                    if (DsgApproveCase.Status.started.getCode().intValue() == approveCase.getStatus().intValue()) {
                                        engine.forward(approveCase);
                                    }
                                } catch (Exception e) {
                                    log.error("推實例異常：", e);
                                    throw new RRException("推實例異常");
                                }
                            }
                        });

                    } else {
                        throw new RRException("無業務申請單狀態數據！");
                    }
                } finally {
                    if (CollectionUtil.isNotEmpty(keyList)) {
                        keyList.forEach(I -> leveldbAccess.delete(I));
                    }
                }
            } else {
                throw new RRException("無過1元數據！");
            }
        }
    }
}
